import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Map;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.events.ServerMessageEvent;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.event.listeners.ServerMessageListener;
import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Methods;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class EveryRuneCrafter extends Script implements ServerMessageListener,
		PaintListener {

	private final int Altar = 2478, Exit = 2465, wait1 = 50, wait2 = 250;
	private final int[] tiara = { 5527, 5529, 5531, 5535, 5537, 5533 },
			essence = { 1436, 7936 };
	private boolean tally, inAltar = false;
	private RSTile[] path;
	private final long startTime = System.currentTimeMillis();
	private RSTile bank_Tile, inRock_Tile, outRock_Tile, destination;
	private int type, talisman, bankID, used = 0, tries = 0, curCount,
			made = 0;
	private final int air_Bank = 11758, mind_Bank = 11758, water_Bank = 2213,
			earth_Bank = 11402, fire_Bank = 27663, body_Bank = 26972;
	private String doing = "Starting";

	@Override
	public String getAuthor() {
		return "Fusion89k";
	}

	@Override
	public String getName() {
		return "Every Rune Crafter";
	}

	@Override
	public String getScriptCategory() {
		return "Runecraft";
	}

	@Override
	public String getScriptDescription() {
		return "<html>\n"
				+ "<head></head>\n"
				+ "<body>\n"
				+ "<center>"
				+ "<h2>"
				+ getName()
				+ "</h2>"
				+ "</center>\n"
				+ "<b>Author:</b> "
				+ getAuthor()
				+ "<br />"
				+ "<b>Version:</b> "
				+ getVersion()
				+ "<br><br><br>"
				+ "<form>Rune Type:<input type=\"radio\" name=\"type\" value=\"1\" checked=\"checked\"> Air "
				+ "<input type=\"radio\" name=\"type\" value=\"2\"> Mind"
				+ "<input type=\"radio\" name=\"type\" value=\"3\"> Water "
				+ "<input type=\"radio\" name=\"type\" value=\"4\"> Earth "
				+ "<input type=\"radio\" name=\"type\" value=\"5\"> Fire "
				+ "<input type=\"radio\" name=\"type\" value=\"6\"> Body "
				+ "<BR></form>"
				+ "<form>Talisman:<input type=\"radio\" name=\"tally\" value=\"talisman\">"
				+ "Tiara:<input type=\"radio\" name=\"tally\" value=\"tiara\" checked=\"checked\"><br /></form>"
				+ "</body>\n" + "</html>";

	}

	@Override
	public double getVersion() {
		return 1.5;
	}

	private boolean isMoving() {
		if (!getMyPlayer().isMoving()) {
			return false;
		}
		if (inAltar) {
			return true;
		}
		setCompass('n');
		if (destination != null
				&& Methods.distanceBetween(path[0], destination) > 5
				&& Methods.distanceBetween(path[path.length - 1], destination) > 5) {
			if (distanceTo(destination) < 6) {
				return false;
			}
		}
		return true;
	}

	private RSTile locate() {
		RSTile min = path[0];
		for (int i = 1; i < path.length; i++) {
			if (distanceTo(path[i]) < distanceTo(min)) {
				min = path[i];
			}
		}
		return min;
	}

	@Override
	public int loop() {
		setCameraAltitude(true);
		if (getInventoryCount(talisman) == 0 && tally && !isCarryingItem(tiara)
				&& !tally) {
			log("No Talisman or Tiara");
			stopAllScripts();
		}
		if (isMoving() || getMyPlayer().getAnimation() != -1) {
			return random(0, 100);
		}
		if (needBank()) {
			if (tries >= 5) {
				log("Bank Fail");
				stopAllScripts();
			}
			if (findObject(Altar + type - 1) != null && !inAltar) {
				inAltar = true;
				return random(wait1, wait2);
			}
			if (inAltar) {
				doing = "Exiting";
				final RSObject ext = findObject(Exit + type - 1);
				if (ext == null) {
					inAltar = false;
					return random(wait1, wait2);
				}
				if (!tileOnScreen(ext.getLocation())) {
					walkTileMM(randomTile(ext.getLocation(), 1));
				}
				atObject(ext, "Use");
				return random(wait1, wait2);
			}
			if (!tileOnScreen(bank_Tile)) {
				doing = "Walking to Bank";
				walk(true);
				return random(wait1, wait2);
			}
			if (!bank.getInterface().isValid()) {
				doing = "Finding Bank";
				final RSObject booth = findObject(bankID);
				if (booth == null) {
					return random(wait1, wait2);
				}
				if (!tileOnScreen(booth.getLocation())) {
					rotate();
				}
				if (type == 5) {
					atObject(booth, "Bank");
				} else {
					atObject(booth, "Use-Quickly");
				}
				return random(wait1, wait2);
			}
			if (bank.getInterface().isValid()) {
				doing = "Depositing";
				bank.depositAllExcept(essence[0], essence[1], talisman);
				doing = "Withdrawing";
				clickMouse(random(38, 73), random(92, 123), false);
				pause();
				atMenu("but");
				tries++;
			}
			return random(wait1, wait2);
		} else {
			tries = 0;
			curCount = getInventoryCount(essence);
			if (findObject(Altar + type - 1) != null && !inAltar) {
				inAltar = true;
				return random(wait1, wait2);
			}
			if (!tileOnScreen(outRock_Tile) && !inAltar) {
				doing = "Walking to Rock";
				walk(false);
				return random(wait1, wait2);
			}
			if (!inAltar) {
				doing = "Entering Rock";
				if (tally) {
					atInventoryItem(talisman, "Use");
				}
				if (!tileOnScreen(outRock_Tile)) {
					rotate();
				}
				clickMouse(Calculations
						.tileToScreen(randomTile(outRock_Tile, 1)), true);
				return random(wait1, wait2);
			} else {
				doing = "Finding Altar";
				final RSObject alt = findObject(Altar + type - 1);
				if (alt == null) {
					inAltar = false;
					return random(wait1, wait2);
				}
				if (!tileOnScreen(alt.getLocation())) {
					doing = "Walking to Altar";
					walkTileMM(randomTile(alt.getLocation()));
					return random(wait1, wait2);
				}
				doing = "Crafting";
				clickMouse(randomPoint(Calculations.tileToScreen(inRock_Tile)),
						true);
				return random(wait1, wait2);
			}
		}
	}

	private boolean needBank() {
		if (getInventoryCount(essence) <= 0) {
			return true;
		}
		return false;
	}

	@Override
	public void onFinish() {
		Bot.getEventManager().removeListener(PaintListener.class, this);
	}

	public void onRepaint(final Graphics g) {
		if (isLoggedIn()) {
			long millis = System.currentTimeMillis() - startTime;
			final long hours = millis / (1000 * 60 * 60);
			millis -= hours * 1000 * 60 * 60;
			final long minutes = millis / (1000 * 60);
			millis -= minutes * 1000 * 60;
			final long seconds = millis / 1000;
			// 173 and 80 decide width and height respectively
			final int topX = 515 - 190, topY = 337 - 80, x = topX + 5;
			int y = topY + 5;
			g.setColor(new Color(0, 100, 0, 100));
			g.fill3DRect(topX, topY, 515 - topX, 337 - topY, true);
			g.setColor(Color.green);
			g.drawString("Runtime: " + hours + "h " + minutes + "min "
					+ seconds + "sec.", x, y += 15);
			g.drawString("Crafted: " + made + " Runes.", x, y += 15);
			g.drawString("Used: " + used + " essence.", x, y += 15);
			g.drawString("Status: " + doing, x, y += 15);
		}
	}

	@Override
	public boolean onStart(final Map<String, String> args) {
		type = Integer.parseInt(args.get("type"));
		switch (type) {
		case 1:
			outRock_Tile = new RSTile(2985, 3292);
			inRock_Tile = new RSTile(2844, 4834);
			talisman = 1438;
			bankID = air_Bank;
			path = new RSTile[] { new RSTile(3015, 3357),
					new RSTile(3008, 3346), new RSTile(3008, 3332),
					new RSTile(3006, 3318), new RSTile(2995, 3310),
					new RSTile(2996, 3296), new RSTile(2987, 3294) };
			break;
		case 2:
			outRock_Tile = new RSTile(2982, 3514);
			inRock_Tile = new RSTile(2786, 4841);
			talisman = 1448;
			bankID = mind_Bank;
			path = new RSTile[] { new RSTile(2945, 3370),
					new RSTile(2955, 3382), new RSTile(2965, 3391),
					new RSTile(2969, 3405), new RSTile(2980, 3415),
					new RSTile(2987, 3426), new RSTile(2980, 3441),
					new RSTile(2971, 3454), new RSTile(2974, 3464),
					new RSTile(2971, 3478), new RSTile(2976, 3491),
					new RSTile(2979, 3501), new RSTile(2980, 3512) };
			break;
		case 3:
			outRock_Tile = new RSTile(3185, 3165);
			inRock_Tile = new RSTile(3484, 4836);
			talisman = 1444;
			bankID = water_Bank;
			path = new RSTile[] { new RSTile(3094, 3243),
					new RSTile(3102, 3232), new RSTile(3112, 3222),
					new RSTile(3125, 3215), new RSTile(3141, 3213),
					new RSTile(3151, 3204), new RSTile(3160, 3192),
					new RSTile(3164, 3177), new RSTile(3175, 3165),
					new RSTile(3183, 3166), };
			break;
		case 4:
			outRock_Tile = new RSTile(3306, 3474);
			inRock_Tile = new RSTile(2658, 4841);
			talisman = 1440;
			bankID = earth_Bank;
			path = new RSTile[] { new RSTile(3253, 3421),
					new RSTile(3264, 3429), new RSTile(3279, 3429),
					new RSTile(3284, 3443), new RSTile(3289, 3457),
					new RSTile(3298, 3465), new RSTile(3304, 3473) };
			break;
		case 5:
			outRock_Tile = new RSTile(3313, 3255);
			inRock_Tile = new RSTile(2585, 4838);
			talisman = 1442;
			bankID = fire_Bank;
			path = new RSTile[] { new RSTile(3382, 3267),
					new RSTile(3368, 3267), new RSTile(3352, 3267),
					new RSTile(3335, 3269), new RSTile(3326, 3264),
					new RSTile(3324, 3248), new RSTile(3310, 3252) };
			break;
		case 6:
			outRock_Tile = new RSTile(3053, 3445);
			inRock_Tile = new RSTile(2523, 4840);
			talisman = 1446;
			bankID = body_Bank;
			path = new RSTile[] { new RSTile(3092, 3491),
					new RSTile(3082, 3483), new RSTile(3081, 3471),
					new RSTile(3073, 3460), new RSTile(3067, 3447),
					new RSTile(3054, 3443) };
			break;
		default:
			return false;
		}
		bank_Tile = path[0];
		if (args.get("tally").equals("tiara")) {
			tally = false;
		} else {
			tally = true;
		}
		return true;
	}

	private void pause() {
		wait(random(wait1, wait2));
	}

	private Point randomPoint(final Point click) {
		return new Point(click.x + random(-5, 5), click.y + random(-5, 5));
	}

	private RSTile randomTile(final RSTile location) {
		return randomTile(location, 2);
	}

	private RSTile randomTile(final RSTile location, final int rand) {
		final int x = location.getX(), y = location.getY();
		return new RSTile(random(x - rand, x + rand),
				random(y - rand, y + rand));
	}

	private void rotate() {
		setCameraRotation(getCameraAngle() + random(170, 180));
	}

	public void serverMessageRecieved(final ServerMessageEvent e) {
		final String word = e.getMessage().toLowerCase();
		if (word.contains("bind")) {
			used += curCount;
			curCount = 0;
		} else if (word.contains("portal")) {
			made += Math.max(getInventoryCount(getInventoryArray()[0]),
					getInventoryCount(getInventoryArray()[1]));
			inAltar = false;
		} else if (word.contains("force take")) {
			inAltar = true;
		} else if (word.contains("only have one")) {
			log("Only one essence left - Logging out");
			stopAllScripts();
		}
	}

	private void walk(final boolean toBank) {
		if (getEnergy() >= random(60, 100)) {
			setRun(true);
		}
		final RSTile start = locate();
		int loc = 0;
		for (int i = 0; i < path.length; i++) {
			if (start.equals(path[i])) {
				loc = i;
				break;
			}
		}
		if (toBank) {
			if (loc == 0) {
				walkTileMM(randomTile(path[0]));
				return;
			}
			destination = randomTile(path[loc - 1]);
			walkTileMM(destination);
		} else {
			if (loc == path.length - 1) {
				walkTileMM(randomTile(path[path.length - 1]));
				return;
			}
			destination = randomTile(path[loc + 1]);
			walkTileMM(destination);
		}
	}
}